"use strict";

function mm_tron(config) {
    this.config = Object.assign({
        name: "",
        contract_address: "",
        chainId: 3,
        precision: Math.pow(10, 6)
    }, config);

    /**
     *褰撳墠鍦板潃
     */
    this.address = "";

    /**
     * 浣欓
     */
    this.balance = 0;

    /**
     * 鏂规硶闆嗗悎
     */
    this.methods = {};

    /**
     * abi鍔犺浇涓紝true涓哄姞杞戒腑锛宖alse涓烘湭鍔犺浇
     */
    this.loading = false;
}


/**
 * 鍒濆鍖�
 * @param {Function} func 鍥炶皟鍑芥暟
 * @return {String} 
 */
mm_tron.prototype.init = function (func) {
    if (window.tronWeb && tronWeb.defaultAddress.base58) {
        var addr = tronWeb.defaultAddress.base58;
        if (typeof (addr) == "string") {
            this.address = addr
        } else {
            this.address = addr[0]
        }
        this.utils = tronWeb.utils;
        if (func) {
            func();
        }
    }
    return this.address;
};

/**
 * 鑾峰彇鍚堢害鏂规硶闆嗗悎
 */
mm_tron.prototype.get_methods = async function () {
    if (!window.tronWeb) {
        console.error('not tronWeb');
        return;
    }

    var obj = await tronWeb.trx.getContract(this.config.contract_address);
    this.instance = await tronWeb.contract().at(this.config.contract_address);
    var arr = obj.abi.entrys;

    for (var i = 0; i < arr.length; i++) {
        var o = arr[i];

        if (o.stateMutability == "view") {
            this.methods[o.name] = function () {
                return this.instance[o.name].apply(this.instance, arguments).call();
            };
        } else {
            this.methods[o.name] = function () {
                return this.instance[o.name].apply(this.instance, arguments).send();
            };
        }
    }

    return obj;
};

/**
 * 瀛楃涓茶浆16杩涘埗
 * @param {String} str
 * @return {String} 杩斿洖16杩涘埗鍊�
 */
mm_tron.prototype.toHex = function (str) {
    if (str && window.tronWeb) {
        return tronWeb.toHex(str);
    }
    return "";
};

/**
 * 16杩涘埗杞瓧绗︿覆
 * @param {String} hex 16杩涘埗鍊�
 * @return {String} 杩斿洖瀛楃涓�
 */
mm_tron.prototype.toStr = function (hex) {
    var trimedStr = hex.trim();
    var rawStr = trimedStr.substr(0, 2).toLowerCase() === "0x" ? trimedStr.substr(2) : trimedStr;
    var len = rawStr.length;

    if (len % 2 !== 0) {
        alert("Illegal Format ASCII Code!");
        return "";
    }

    var curCharCode;
    var resultStr = [];

    for (var i = 0; i < len; i = i + 2) {
        curCharCode = parseInt(rawStr.substr(i, 2), 16); // ASCII Code Value

        resultStr.push(String.fromCharCode(curCharCode));
    }

    return resultStr.join("");
};

/**
 * 琛ラ浂
 * @param {String} value 闇€瑕佽ˉ闆剁殑瀛楃涓�
 * @return {String} 琛ラ浂鍚庣殑瀛楃涓�
 */
mm_tron.prototype.full_zore = function (value) {
    var len = 64 - value.length;
    var val = "";

    for (var i = 0; i < len; i++) {
        val += "0";
    }

    return val + value;
};

/**
 * 杞�16杩涘埗
 * @param {String} num 鏁板€�
 * @param {Number} map 绮惧害
 * @return {String} 杞崲缁撴灉
 */
mm_tron.prototype.toChage_16 = function (num, map) {
    return '0x' + (num * (map || this.config.precision)).toString(16);
};

/**
 * 杞�10杩涘埗
 * @param {String} num 鏁板€�
 * @param {Number} map 绮惧害
 * @return {String} 杞崲缁撴灉
 */
mm_tron.prototype.toChage_10 = function (value, map) {
    return parseInt(value.replace('0x', ''), 16) / (map || this.config.precision);
};

/**
 * 杞负鍙傛暟
 * @param {String} name 璇锋眰鏂规硶鍚嶇О
 * @param {Array} param 璇锋眰鍙傛暟闆嗗悎
 * @return {Object} 杩斿洖鍙傛暟
 */
mm_tron.prototype.to_param = function (name) {
    var code = this.methods[name];
    var data = code;

    for (var i = 0; i < (arguments.length <= 1 ? 0 : arguments.length - 1); i++) {
        var o = i + 1 < 1 || arguments.length <= i + 1 ? undefined : arguments[i + 1];

        if (typeof o == 'string') {
            data += this.full_zore(o.replace('0x', ''));
        } else if (typeof o == 'number') {
            data += this.full_zore(this.toChage_16(o, 1).replace('0x', ''));
        }
    }

    return {
        to: this.config.contract_address,
        // 蹇呴渶锛屽悎鍚屽彂甯冩湡闂撮櫎澶� Required except during contract publications.
        from: this.address,
        // 鍙戦€佸湴鍧€ must match user's active address.
        data: data,
        // '0x7f7465737432000000000000000000000000000000000000000000000000000000600057', // 鍙€夛紝浣嗙敤浜庡畾涔夋櫤鑳藉悎绾︾殑鍒涘缓鍜屼氦浜� Optional, but used for defining smart contract creation and interaction.
        chainId: this.config.chainId // 鐢ㄤ簬闃叉璺ㄥ尯鍧楅摼鐨勪簨鍔￠噸鐢紝鐢盡etaMask鑷姩濉厖 Used to prevent transaction reuse across blockchains. Auto-filled by MetaMask.

    };
};

/**
 * 鎺ㄩ€� 鈥斺€� 鍙戦€佸埌閾句笂
 * @param {String} name 鏂规硶鍚�
 * @param {String} value 鏁板€�
 * @param {Array} param 鍙傛暟
 */
mm_tron.prototype.send = async function (name, value) {
    if (!name) {
        return;
    }

    for (var _len = arguments.length, param = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
        param[_key - 2] = arguments[_key];
    }

    console.log(this.config.contract_address + " send ".concat(name, " req"), param);

    if (!window.tronWeb) {
        return;
    }

    try {
        if (!this.instance) {
            this.instance = await tronWeb.contract().at(this.config.contract_address);
        }
        if (this.instance) {
            if (this.instance[name]) {
                var res = await this.instance[name].apply(this.instance, param).send({
                    feeLimit: 100000000,
                    callValue: value || 0,
                    shouldPollResponse: true
                });
                console.log(`send ${name} res`, res);

                return res;
            } else {
                console.error(this.config.contract_address + ": " + name + " is undefined");
            }
        }
    } catch (e) {
        console.log(this.config.contract_address + "鐨勬柟娉� " + name + " 閿欒", e);
    }
};

/**
 * 鍛煎彨 鈥斺€� 鎺ユ敹鍒版湰鍦�
 * @param {String} name 鏂规硶鍚�
 * @param {String} value 鏁板€�
 * @param {Array} param 鍙傛暟
 */
mm_tron.prototype.call = async function (name, value) {
    if (!name) {
        return;
    }

    for (var _len2 = arguments.length, param = new Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) {
        param[_key2 - 2] = arguments[_key2];
    }

    console.log(this.config.contract_address + " call ".concat(name, " req"), param);

    if (!window.tronWeb) {
        return;
    }

    try {
        if (!this.instance && !this.loading) {
            this.loading = true;
            this.instance = await tronWeb.contract().at(this.config.contract_address);
            this.loading = false;
        }
        if (this.instance) {
            if (this.instance[name]) {
                var res = await this.instance[name].apply(this.instance, param).call({
                    feeLimit: 100000000,
                    callValue: value || 0,
                    shouldPollResponse: true
                });
                console.log(`call ${name} res`, res);

                return res;
            } else {
                console.error(this.config.contract_address + ": " + name + " is undefined");
            }
        }
    } catch (e) {
        console.log(this.config.contract_address + "鐨勬柟娉� " + name + " 閿欒", e);
    }
};

/**
 * 杞埌鍚堢害鍦板潃
 * @param {String} form_address 鍙戦€佸湴鍧€
 * @param {String} to_address 鎺ユ敹鍦板潃
 * @param {Number} amount 杞处閲戦
 * @param {String} value 鏁板€�
 * @return {object} 杩斿洖鎵ц缁撴灉
 */
mm_tron.prototype.trade = async function (form_address, to_address, amount) {
    var value = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : '0x00';

    // console.log('trade req', pm);
    if (!window.tronWeb) {
        return;
    }

    try {
        var tx = await tronWeb.transactionBuilder.sendTrx(to_address || this.config.contract_address, 10, form_address);
        var signedTx = await tronWeb.trx.sign(tx);
        var broastTx = await tronWeb.trx.sendRawTransaction(signedTx);
        return broastTx;
    } catch (e) {
        console.log(this.config.contract_address + "鐨� trade 閿欒", e);
    }
};

/**
 * 杞埌鍚堢害鍦板潃
 * @param {String} name 鏂规硶鍚�
 * @param {Array} param 鍙傛暟
 * @return {}
 */
mm_tron.prototype.get_balance = async function (address) {
    var o = await tronWeb.trx.getBalance(address);
    return o / this.config.precision;
};

/**
 * 璀︾ず
 * @param {String} message 娑堟伅鍐呭
 * @param {String} type
 */
mm_tron.prototype.alert = async function (message) {
    var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "error";
    console.log(message, type);
};

/**
 * 璇锋眰
 * @param {String} method 鏂规硶
 * @param {Array} params 鍙傛暟
 * @param {Funciton} func 鍥炶皟鍑芥暟
 * @return {Object} 鎵ц缁撴灉
 */
mm_tron.prototype.req = async function () {
    var _this = this;

    var method = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'eth_accounts';
    var params = arguments.length > 1 ? arguments[1] : undefined;
    var func = arguments.length > 2 ? arguments[2] : undefined;

    if (func) {
        ethereum.request({
            method: method,
            params: params
        }).then(function (res) {
            func(res);
        }).catch(function (error) {
            if (error.code === 4001) {
                // EIP-1193 userRejectedRequest error
                _this.alert('Please connect to MetaMask.');
            } else {
                _this.alert(error);
            }
        });
    } else {
        return await ethereum.request({
            method: method,
            params: params
        });
    }
};

/**
 * 鑾峰彇璐︽埛
 */
mm_tron.prototype.get_accounts = async function () {
    return await this.req("eth_requestAccounts", {});
};

/**
 * 鑾峰彇鍦板潃
 */
mm_tron.prototype.login = async function () {
    var res = await this.req("eth_requestAccounts", {});

    if (res && res.length) {
        var address = res[0];
        this.address = address;
        return address;
    }
};

/**
 * 鏄惁宸茬櫥褰�
 * @return {object} 鎵ц缁撴灉
 * @return {Boolean} 鐧诲綍鎴愬姛杩斿洖true, 澶辫触杩斿洖false
 */
mm_tron.prototype.isLink = function () { };

/**
 * 鑾峰彇鍦板潃
 */
mm_tron.prototype.get_address = function () {
    var address = this.init();

    if (address) {
        this.address = address;
        return address;
    }

    return null;
};

/**
 * 鏌ヨ鎺堟潈
 * @param {String} userAddress 鐢ㄦ埛鍦板潃
 * @param {String} contractAddress 浠ｅ竵鍚堢害鍦板潃
 * @return {String} 鏄惁鏈夋巿鏉�
 */
mm_tron.prototype.allowance = async function (userAddress, contractAddress) {
    // TGEA5wkr1A6pkmwdLrepv63dNKi6rFinWL   lp-pool
    // TCPwAERu17bxQGBU2BnrXzjJUCqW7h2X4U   lp-token
    var functionSelector = "allowance(address,address)";
    var parameter = [{
        type: "address",
        value: userAddress
    }, {
        type: 'address',
        // 姹犲瓙鍦板潃
        value: this.config.contract_address
    }];
    var options = {};
    var res = await tronWeb.transactionBuilder.triggerConstantContract(contractAddress, functionSelector, options,
        parameter);

    if (res && res.constant_result.length > 0) {
        return this.toChage_10(res.constant_result[0]);
    }

    return 0;
};

/**
 * 鎺堟潈
 * @param {String} contractAddress 鎺堟潈鍦板潃
 * @return {String} 鎺堟潈缁撴灉
 */
mm_tron.prototype.approve = async function (contractAddress) {
    var functionSelector = "approve(address,uint256)";
    var parameter = [{
        type: "address",
        value: this.config.contract_address
    }, {
        type: "uint256",
        value: "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
    }];
    var options = {};
    var tx = await tronWeb.transactionBuilder.triggerSmartContract(contractAddress, functionSelector, options, parameter);
    var signedTx = await tronWeb.trx.sign(tx.transaction);
    return await tronWeb.trx.sendRawTransaction(signedTx);
};

/**
 * 鑾峰彇浣欓
 * @param {String} userAddress 鐢ㄦ埛鍦板潃
 */
mm_tron.prototype.balanceOf = async function (userAddress) {
    var contractAddress = this.config.contract_address;
    var functionSelector = "balanceOf(address)";
    var parameter = [{
        type: "address",
        value: userAddress
    }];
    var options = {};
    return await tronWeb.transactionBuilder.triggerConstantContract(contractAddress, functionSelector, options, parameter);
};

mm_tron.prototype.stake = async function (amount) {
    var contractPool = this.config.contract_address;
    var ins = await tronWeb.contract().at(contractPool);
    return await ins.stake(amount).send({
        feeLimit: 100000000,
        callValue: 0,
        shouldPollResponse: true
    });
};

if (window.$) {
    $.mm_tron = mm_tron;
}